#include "gsm.h"
#include "gsmio.h"

//extern Config_t  *CONFIG;

static GSM_STATUS_t gsm_status_v = GSM_INACTIVE;

//#define gsm_status_set(s) (gsm_status_v = (s))
#define GSM_RETURN(status) {gsm_status_set(status); return status;}

void gsm_status_set(GSM_STATUS_t s)
{
  gsm_status_v = s;
  if (s == GSM_ERROR)
    s = GSM_ERROR;
}

static volatile unsigned int  localerror;
static volatile GSM_STATUS_t  sret;
/* ------------------------------------------------------------------ */
/* PUBLIC FUNCTIONS                                                   */
/* ------------------------------------------------------------------ */
GSM_STATUS_t gsm_enable(char* apn, GSM_SIM_t sim, int baud){
  //debug_printf("gsm_enable()\r\n");
  if (gsm_status() != GSM_INACTIVE) {
    gsm_disable();
  }


  gsmio_power_off();
  GSMIO_SIM(sim);
  gsmio_power_on();
  modem_init(baud);

  gsmio_on();
/*
  while(1){
  gsmio_command("AT+CSQ\r\n", "OK", 2000);
  }
  */
  if (gsmio_command("ATE0\r\n", "OK", 1000) != GSM_CMD_OK){
    gsm_status_set(GSM_ERROR);
    return GSM_ERROR;
  }
 
  for (int i = 0; i < 35; i++){
    if (gsmio_command("AT+CGREG?\r\n", "+CGREG: 0,1", 1000) == GSM_CMD_OK) 
      break;
  }

  if (gsmio_command("AT+CGATT=1\r\n", "OK", 10000) != GSM_CMD_OK)
    GSM_RETURN(GSM_ERROR);
  ctl_timeout_wait(msec(500));
  gsmio_command("AT+CGDCONT=1,\"IP\",\"", "", 0);
//  gsmio_command(CONFIG->Network.Sim[sim].APN, "", 0);
  gsmio_command(apn, "", 0);
  if (gsmio_command("\"\r\n", "OK", 5000) != GSM_CMD_OK)
    GSM_RETURN(GSM_ERROR);
  ctl_timeout_wait(msec(500));
  gsmio_command("AT+CSTT=\"", "", 0);
//  gsmio_command(CONFIG->Network.Sim[sim].APN, "", 0);
  gsmio_command(apn, "", 0);
  if (gsmio_command("\",\"\",\"\"\r\n", "OK", 1000) != GSM_CMD_OK)
    GSM_RETURN(GSM_ERROR);
  ctl_timeout_wait(msec(500));
  if (gsmio_command("AT+CIICR\r\n", "OK", 20000) != GSM_CMD_OK)
    GSM_RETURN(GSM_ERROR);
  ctl_timeout_wait(msec(500));
  gsmio_command("AT+CIFSR\r\n", "OK", 2000);
  if (gsmio_command("AT+CIPSTATUS\r\n", "STATE: IP STATUS", 2000)!= GSM_CMD_OK)
    GSM_RETURN(GSM_ERROR);
  ctl_timeout_wait(msec(5000));
  if (gsmio_command("AT+CIPHEAD=1\r\n", "OK", 2000) != GSM_CMD_OK)
    GSM_RETURN(GSM_ERROR);

#ifdef SIM300
  if (gsmio_command("AT+CDNSORIP=1\r\n", "OK", 1000) != GSM_CMD_OK)
    GSM_RETURN(GSM_ERROR);
#endif

  gsm_status_set(GSM_DISCONNECTED);
  return GSM_DISCONNECTED;
}

GSM_STATUS_t gsm_connect(char* host, unsigned int port, unsigned int TcpTimeout)
{
  
  char port_str[5] = "";
  itoa((port>65535)?(65535):(port), port_str, 10);
  gsmio_command("AT+CIPSTART=\"TCP\",\"", "", 0);
  gsmio_command(host, "", 0);
  gsmio_command("\",\"", "", 0);
  gsmio_command(port_str, "", 0);
//  if (gsmio_command("\"\r\n", "CONNECT OK", CONFIG->Network.TcpTimeout) != GSM_CMD_OK){
  if (gsmio_command("\"\r\n", "CONNECT OK", TcpTimeout) != GSM_CMD_OK){
    gsm_status_set(GSM_ERROR);
    //debug_printf("gsm_connect() - error\r\n");
    return GSM_ERROR;
  }
  //debug_printf("gsm_connect() - ok\r\n");
  gsm_status_set(GSM_CONNECTED);
  return GSM_CONNECTED;
}

GSM_STATUS_t gsm_disconnect()
{
  //debug_printf("gsm_disconnect()\r\n");
  if (gsmio_command("AT+CIPCLOSE\r", "CLOSE OK", 3000) != GSM_CMD_OK){
    gsm_status_set(GSM_ERROR);
    return GSM_ERROR;
  }
  gsm_status_set(GSM_DISCONNECTED);
  return GSM_DISCONNECTED;
}

GSM_STATUS_t gsm_disable()
{
  //debug_printf("gsm_disable()\r\n");
  if (gsm_status() != GSM_INACTIVE){
    gsm_disconnect();
    gsmio_command("AT+CIPSHUT\r", "SHUT OK", 5000);
    gsmio_command("AT+CGATT=0\r\n", "OK", 1000);
    gsmio_command("AT+CPOWD=1\r\n", "NORMAL POWER DOWN", 2000);
  }
  gsmio_power_off();
  gsm_status_set(GSM_INACTIVE);
  return GSM_INACTIVE;
}

GSM_STATUS_t gsm_status()
{
  return gsm_status_v;
}

GSM_STATUS_t gsm_transmit_raw(char* request, unsigned int length)
{
  
  char str[18] = "";
  //if (gsmio_command("AT+CIPSTATUS\r\n", "STATE: CONNECT OK", 3000) != GSM_CMD_OK)
  //  debug_printf("gsm_transmit() - bad status\r\n");
  int  str_len = snprintf(str, 18, "AT+CIPSEND=%d\r\n", length);
  if (gsmio_command_n(str, str_len, ">", 2000, 1) != GSM_CMD_OK){
    gsm_status_set(GSM_ERROR);
    //debug_printf("gsm_transmit() - error 0\r\n");
    return GSM_ERROR;
  }
  if (gsmio_command_n(request, length, "SEND OK", 20000, 0) != GSM_CMD_OK){
    gsm_status_set(GSM_ERROR);
    //debug_printf("gsm_transmit() - error 1\r\n");
    return GSM_ERROR;
  }
  gsm_status_set(GSM_CONNECTED);
  //debug_printf("gsm_transmit() - ok\r\n");
  return GSM_CONNECTED;
}


/* Transmit RTEA encrypted data to a server */
/*
GSM_STATUS_t gsm_transmit_json(char* request, unsigned int length, json_node** response, bool encrypt)
{
  
  if (encrypt){
    while (length % 8 != 0) request[length++] = ' '; // Increase buffer to fit 64bit blocks
    rtea_encrypt((unsigned int*)request, length / sizeof(unsigned int), RTEA_KEY); // Encrypt all blocks
  }
  else {
    while (length % 8 != 0) length++; // Increase buffer to fit 64bit blocks
  }
  if (gsm_transmit_raw(request, length) == GSM_ERROR){
    gsm_status_set(GSM_ERROR);
    return GSM_ERROR;
  }
  if (gsmio_json_receive(5000, response) == GSM_ERROR) GSM_RETURN(GSM_ERROR);

  gsm_status_set(GSM_CONNECTED);
  return GSM_CONNECTED;
}
*/

/* Transmit raw data to a server */
GSM_STATUS_t gsm_http_download(char* host, char* path, char* filename, unsigned int* crc32, unsigned long timeout_ms)
{
  FIL file;
  localerror=0;
  if (f_open(&file, filename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK){
    localerror=1;
    return GSM_CMD_ERROR;
  }

  char request[128] = "";
  unsigned int length = snprintf(request, 128, "GET %s HTTP/1.0\r\nHOST: %s\r\n\r\n", path, host);
  sret=gsm_transmit_raw(request, length);
  if ( sret == GSM_ERROR){
    f_close(&file);
    gsm_status_set(GSM_ERROR);
    localerror=2;
    return GSM_ERROR;
  }
  sret=gsmio_http_receive(&file, crc32, timeout_ms);  // при запросе на форматирование вернется GSM_FORMAT_COMMAND
  if( sret == GSM_CMD_FORMAT){
    f_close(&file);
    gsm_status_set(GSM_FORMAT_COMMAND);
    localerror=10;
    return GSM_FORMAT_COMMAND;
  }
  if (sret != GSM_CMD_OK){
    f_close(&file);
    gsm_status_set(GSM_ERROR);
    localerror=3;
    return sret;
  };
  FRESULT fr = f_close(&file);
  if (fr != FR_OK){
    gsm_status_set(GSM_ERROR);
    localerror=4;
    return GSM_ERROR;
  }
  gsm_status_set(GSM_CONNECTED);
  return GSM_CONNECTED;
}
 